package com.zhaochao.validation.helper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ReflectUtil;
import com.zhaochao.validation.annotation.AssertFalseOn;
import com.zhaochao.validation.annotation.AssertTrueOn;
import com.zhaochao.validation.annotation.EnableCondition;
import com.zhaochao.validation.annotation.NotNullOn;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Map;

@Slf4j
public class ConditionValidator implements ConstraintValidator<EnableCondition, Object> {

    private final ExpressionParser parser = new SpelExpressionParser();
    private final EvaluationContext elContext = new StandardEvaluationContext();

    @Override
    public boolean isValid(Object validatedBean, ConstraintValidatorContext context) {
        fillBean(validatedBean);
        Field[] fields = ReflectUtil.getFields(validatedBean.getClass());
        Boolean res = true;
        for (Field field : fields) {
            //获取当前字段
            Object fieldValue = ReflectUtil.getFieldValue(validatedBean, field.getName());
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
                if (annotation instanceof NotNullOn) {
                    NotNullOn notNullOn = (NotNullOn) annotation;
                    res = res && isValid(NotNullOn.class.getName(), notNullOn.message(), context, notNullOn.on(), field.getName(), fieldValue);
                }
                if (annotation instanceof AssertTrueOn) {
                    AssertTrueOn assertTrueOn = (AssertTrueOn) annotation;
                    res = res && isValid(AssertTrueOn.class.getName(), assertTrueOn.message(), context, assertTrueOn.on(), field.getName(), fieldValue);
                }
                if (annotation instanceof AssertFalseOn) {
                    AssertFalseOn assertTrueOn = (AssertFalseOn) annotation;
                    res = res && isValid(AssertFalseOn.class.getName(), assertTrueOn.message(), context, assertTrueOn.on(), field.getName(), fieldValue);
                }
            }

        }
        return res;
    }

    private boolean isValid(String name, String message, ConstraintValidatorContext context, String on, String fieldName, Object fieldValue) {
        Boolean res = true;
        if (parseEl(on)) {
            ConstraintValidator validator = SupportContext.getValidator(name);
            if (!validator.isValid(fieldValue, context)) {
                res = false;
                context.buildConstraintViolationWithTemplate(message)
                        .addPropertyNode(fieldName)
                        .addConstraintViolation();
            }
        }
        return res;
    }


    private void fillBean(Object object) {
        Map<String, Object> map = BeanUtil.beanToMap(object);
        map.forEach((k, v) -> elContext.setVariable(k, v));
    }

    protected Boolean parseEl(String el) {
        Expression expression = parser.parseExpression(el);
        Object value = expression.getValue(elContext);
        return Boolean.valueOf(value.toString());
    }
}
